package com.tma.demo;

import java.lang.ref.WeakReference;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.os.AsyncTask;
import android.os.AsyncTask.Status;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.TextView;
import android.widget.Toast;

public class AsynDeterministicActivity extends Activity implements OnClickListener {

    private static final String TAG = "AsynDeterministicActivity";
    private TextView mTaskProgressTextView;
    private Button mAsynButton;
    private DeterministicTask mAsynTask;
    private CheckBox mCheckBox;

    @SuppressWarnings("deprecation")
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_asyn_deterministic);

        mTaskProgressTextView = (TextView) findViewById(R.id.tv_task_progress);
        mAsynButton = (Button) findViewById(R.id.btn_do_long_task);
        mCheckBox = (CheckBox) findViewById(R.id.cb_use_progress_dialog);

        mAsynButton.setOnClickListener(this);

        mAsynTask = (DeterministicTask) getLastNonConfigurationInstance();
        if (mAsynTask != null) {
            mAsynTask.attach(this);
            mAsynTask.resumeProgressDialogIfNeeded();
        }
    }

    @Override
    protected void onDestroy() {
        if (mAsynTask != null) {
            mAsynTask.hideProgressDialog();
        }
        super.onDestroy();
    }

    @Override
    @Deprecated
    public Object onRetainNonConfigurationInstance() {
        return mAsynTask;
    }

    public void onClick(View v) {
        handleButtonClicked();
    }

    public void updateStatus(String status) {
        mTaskProgressTextView.setText(status);
    }

    public boolean useProgressDialog() {
        return mCheckBox.isChecked();
    }

    private void handleButtonClicked() {
        if (mAsynTask == null || mAsynTask.getStatus() == Status.FINISHED) {
            mAsynTask = new DeterministicTask(this);
            mAsynTask.execute();
            return;
        }
        if (mAsynTask.getStatus() != Status.FINISHED) {
            Toast.makeText(this, "The asyn task is not finished yet", Toast.LENGTH_SHORT).show();
        }
    }

    private class DeterministicTask extends AsyncTask<Void, Integer, Long> implements OnCancelListener {
        private ProgressDialog mProgressDialog;
        private WeakReference<AsynDeterministicActivity> mActivityRef;
        private int mStep = 100;

        public DeterministicTask(AsynDeterministicActivity activity) {
            attach(activity);
        }

        @Override
        protected void onPreExecute() {
            Log.i(TAG, "starting");

            if (mCheckBox.isChecked()) {
                mProgressDialog = buildProgressDialog();
                mProgressDialog.show();
            }
        }

        @Override
        protected Long doInBackground(Void... params) {
            // THIS METHOD RUN ON WORKER THREAD
            // DO NOT UPDATE UI HERE!!!
            long time = System.currentTimeMillis();

            for (int i = 1; i <= mStep; i++) {
                // we want to cancel the task as quickly as possible
//                if (isCancelled()) {
//                    break;
//                }
                Log.i(TAG, "processing " + i);
                publishProgress(i);
                sleep(50); // simulate long task
            }
            time = System.currentTimeMillis() - time;
            return time;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            int progress = values[0];
            AsynDeterministicActivity mActivity = mActivityRef.get();
            if (mActivity != null) {
                mActivity.updateStatus("Processing: " + progress + "/" + mStep);
                if (mProgressDialog != null) {
                    mProgressDialog.setProgress(progress);
                }
            }
        }

        @Override
        protected void onCancelled() {
            Log.i(TAG, "cancel");
            AsynDeterministicActivity activity = mActivityRef.get();
            if (activity != null) {
                if (mProgressDialog != null && mProgressDialog.isShowing()) { 
                    mProgressDialog.cancel();
                }
                activity.updateStatus("Cancelled");
            }
        }

        @Override
        protected void onPostExecute(Long result) {
            // THIS METHOD RUNS ON UI THREAD
            // --> UPDATE YOUR UI HERE
            Log.i(TAG, "done");
            AsynDeterministicActivity activity = mActivityRef.get();
            if (activity == null) {
                Log.i(TAG, "skipped --- no acitivity");
                return;
            }

            if (activity != null) {
                activity.updateStatus("Done in " + Utils.toDebugString(result));
                if (mProgressDialog != null && mProgressDialog.isShowing()) { 
                    mProgressDialog.setOwnerActivity(activity);
                    mProgressDialog.cancel();
                }
            }
        }

        // progress dialog's cancel callback
        public void onCancel(DialogInterface dialog) {
            cancel(true);
        }

        public void attach(AsynDeterministicActivity activity) {
            mActivityRef = new WeakReference<AsynDeterministicActivity>(activity);
        }

        public void hideProgressDialog() {
            if (mProgressDialog != null) {
                mProgressDialog.dismiss();
            }
        }

        public void resumeProgressDialogIfNeeded() {
            AsynDeterministicActivity activity = mActivityRef.get();
            if (getStatus() != Status.FINISHED && activity != null) {
                mProgressDialog = buildProgressDialog();
                mProgressDialog.show();
            }
        }

        private ProgressDialog buildProgressDialog() {
            ProgressDialog pd = new ProgressDialog(mActivityRef.get());
            pd.setTitle("Please wait");
            pd.setMessage("Processing...");
            pd.setIndeterminate(false);
            pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            pd.setMax(mStep);
            pd.setCancelable(true);
            pd.setOnCancelListener(this);
            return pd;
        }

        private void sleep(long time) {
            try {
                Thread.sleep(time);
            } catch (InterruptedException e) {
            }
        }
    }
}
